package net.gdface.facelog.hb;

import com.google.common.base.Supplier;

import gu.simplemq.Channel;
import gu.simplemq.IMessageAdapter;
import gu.simplemq.IMessageQueueFactory;
import gu.simplemq.ISubscriber;
import gu.simplemq.exceptions.SmqUnsubscribeException;
import net.gdface.facelog.mq.BaseServiceHeartbeatListener;
import net.gdface.facelog.mq.ServiceHeartbeatPackage;

import static com.google.common.base.Preconditions.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Objects;
import com.google.common.base.Strings;

/**
 * 动态频道频道侦听<br>
 * 动态频道是指定当服务重启后，频道名会动态改变的频道，
 * 对于这种频道，通过侦听服务心跳判断服务是否重启，如果重启则重新获取频道名继续保持侦听
 * @author guyadong
 *
 * @param <T> 频道的数据类型
 */
public class DynamicChannelListener<T>extends BaseServiceHeartbeatListener {
    public static final Logger logger = LoggerFactory.getLogger(DynamicChannelListener.class);

	private  IMessageAdapter<T> hbAdapter = new IMessageAdapter<T>(){

		@Override
		public void onSubscribe(T t) throws SmqUnsubscribeException {
		}};
	private final Supplier<String> channelSupplier;
	private volatile String channelName ;
	private final ISubscriber subscriber;
	private String channelCatalog = "channel";
	private final Class<T> channelType;
	/**
	 * 构造方法
     * usage:<pre>new DynamicChannelListener&lt;Model&gt;(hbAdapter,channelSupplier,jedisPoolLazy){};</pre>
	 * @param hbAdapter 设备心跳包侦听实例
	 * @param channelType 频道消息数据类型
	 * @param channelSupplier 心跳包频道名的{@link Supplier}实例，用于提供当前的心跳包频道名
	 * @param factory 消息系统工厂类实例
	 */
	public DynamicChannelListener(IMessageAdapter<T> hbAdapter,Class<T> channelType,Supplier<String> channelSupplier, IMessageQueueFactory factory) {
		super();
		if(hbAdapter != null){
			this.hbAdapter = checkNotNull(hbAdapter);
		}
		this.channelSupplier = checkNotNull(channelSupplier,"channelSupplier is null");
		this.subscriber = checkNotNull(factory,"factory is null").getSubscriber();
        this.channelType = checkNotNull(channelType,"channelType is null");
	}
	@Override
	protected boolean doServiceOnline(ServiceHeartbeatPackage t){
		start();
		return true;
	}
	/**
	 * 获取动态频道名,注册侦听频道，启动频道监控
	 * @return 
	 */
	public DynamicChannelListener<T> start(){
		String ch = channelSupplier.get();
		if(!Objects.equal(channelName, ch)){
			stop();
			// 申请新的频道名
			logger.info("Start {} ch:[{}]",channelCatalog,ch);
			subscriber.register(new Channel<T>(ch,channelType,hbAdapter){});
			channelName = ch;
		}
		return this;
	}
	/**
	 * 取消频道订阅，停止频道监控
	 */
	public void stop(){		
		if(null != channelName){
			synchronized (this) {
				if(null != channelName){
					// 注销上一个频道名
					subscriber.unregister(channelName);
					logger.info("unregister last monitor channel :[{}]",channelName);
					channelName = null;				
				}
			}
		}
	}
	/**
	 * @return 返回频道侦听实例
	 */
	public IMessageAdapter<T> getHbAdapter() {
		return hbAdapter;
	}
	/**
	 * 设置频道侦听实例
	 * @param hbAdapter 不可为{@code null}
	 * @return
	 */
	public DynamicChannelListener<T> setHbAdapter(IMessageAdapter<T> hbAdapter) {
		this.hbAdapter = checkNotNull(hbAdapter,"hbAdapter is null");
		return this;
	}
	public DynamicChannelListener<T> setChannelCatalog(String channelCatalog) {
		if(!Strings.isNullOrEmpty(channelCatalog)){
			this.channelCatalog = channelCatalog;
		}
		return this;
	}
}
